
setmetatable = setmetatable
pairs        = pairs 
pcall        = pcall
printd       = debug.print or print

if truetype == nil then
  --- Extended type definitions
  truetype = truetype or type -->without this check when quick iteration 
                              -- is on this might cause the new type function 
                              -- to be referencing itself causing an infinite 
                              -- loop 
  local function type(v)
    local v = v
    local s = truetype(v)
    if s == "table" or s == "userdata" then
      if v.__type then
        s = v.__type
      end 
    end
    return s
  end
  
end
 
module(...) -->name the package according to the filename

local delegate_mt={
  __type   = "delegate",
  __add    = function(t, fun)
    if (type(fun) == "function") or (type(fun) == "functor") then
      t.calls[{}]=fun
    else
      if (type(fun) == "delegate") then 
        for k,v in pairs(fun.calls) do
          t.__add(v)
        end 
      end
    end
    return t
  end, 
  __sub = function(t,fun)
    if (type(fun) == "function") or (type(fun) == "functor") then
      for k,v in pairs(t.calls) do
        if(v == fun) then
          t.calls[k]=nil
          return t
        end  
      end 
    elseif (type(fun) == "table") and (type(fun) == "delegate") then 
      for k,v in pairs(fun.calls) do
        t.__sub(v)
      end 
    end 
    return t    
  end,
  __call   = function(t,...)
    for k,v in pairs(t.calls) do
      b, err = pcall(v,...)
      if err then --if the function causes errors remove it
        printd("removed delegate call")
        t.__sub(v)
      end 
    end
  end,
}  

new = function(d)
  d = d or {}
  d.calls = d.calls or {}
  setmetatable(d,delegate_mt)
  return d
end
